﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Pong_Project.Game_objects;
using Microsoft.Xna.Framework;

namespace Pong_Project
{
    /// <summary>
    /// The CollisionDetector will handle the collision detection in the game. 
    /// This will include smart algoritms to optimize the performance (regarding which objects to compare)
    /// </summary>
    /// 
    class CollisionDetector : IObserver
    {
        private static Vector2 obstacleArea = new Vector2(Game.WindowWidth / 3, Game.WindowWidth * 2 / 3);
        private Ball ball;
        private Bat batLeft, batRight;
        // A list that contains all the obstacles in the board
        private static List<Obstacle> activeObstacles = new List<Obstacle>();

        public CollisionDetector(Bat batLeft, Bat batRight, Ball ball)
        {
            this.ball = ball;
            this.batLeft = batLeft;
            this.batRight = batRight;
        }

        public static float ObstacleAreaLeftBoundary
        {
            get { return obstacleArea.X; }
        }

        public static float ObstacleAreaRightBoundary
        {
            get { return obstacleArea.Y; }
        }

        public void bounceOffObstacleTop()
        {
            ball.VelocityY *= -1.02f;
            if (Math.Abs(ball.VelocityY) > 2.0f) //2.0f is the maxVelocityY of the ball, making a getter to that didn't allow it to be compared to the absolute value
            {
                ball.VelocityY = -2.0f;
            }
        }

        public void bounceOffObstacleBot()
        {
            ball.VelocityY *= -1.02f;
            if (Math.Abs(ball.VelocityY) > 2.0f) //2.0f is the maxVelocityY of the ball, making a getter to that didn't allow it to be compared to the absolute value
            {
                ball.VelocityY = 2.0f;
            }
        }

        public void bounceOffObstacleLeftSide()
        {
            ball.VelocityX *= -1.02f;
            if (Math.Abs(ball.VelocityX) > 2.5f) //2.5f is the maxVelocityX of the ball, making a getter to that didn't allow it to be compared to the absolute value
            {
                ball.VelocityX = -2.5f;
            }
        }

        public void bounceOffObstacleRightSide()
        {
            ball.VelocityX *= -1.02f;
            if (Math.Abs(ball.VelocityX) > 2.5f) //2.5f is the maxVelocityX of the ball, making a getter to that didn't allow it to be compared to the absolute value
            {
                ball.VelocityX = 2.5f;
            }
        }

        public void Update(GameTime gameTime)
        {
            if (ball.Left > ObstacleAreaLeftBoundary && ball.Right < ObstacleAreaRightBoundary)
            {
                foreach (Obstacle obstacle in activeObstacles)
                {
                    if (ball.Intersects(obstacle))
                    {
                        // If the ball hits anywhere on the top of an obstacle, included the top corners
                        if (ball.Intersects(obstacle.EdgeTop))
                        {
                            if (ball.Intersects(obstacle.EdgeRight))
                            {
                                if (ball.VelocityX < 0)
                                {
                                    bounceOffObstacleRightSide();
                                }
                                if (ball.VelocityY > 0)
                                {
                                    bounceOffObstacleTop();
                                }
                            }
                            else if (ball.Intersects(obstacle.EdgeLeft))
                            {
                                if (ball.VelocityX > 0)
                                {
                                    bounceOffObstacleLeftSide();
                                }
                                if (ball.VelocityY > 0)
                                {
                                    bounceOffObstacleTop();
                                }
                            }
                            else
                                bounceOffObstacleTop();
                        }

                        //If the ball hits anywhere on the bottom of the obstacle, included the bottom corners
                        else if (ball.Intersects(obstacle.EdgeBot))
                        {
                            if (ball.Intersects(obstacle.EdgeRight))
                            {
                                if (ball.VelocityX < 0)
                                {
                                    bounceOffObstacleRightSide();
                                }
                                if (ball.VelocityY < 0)
                                {
                                    bounceOffObstacleBot();
                                }
                            }
                            else if (ball.Intersects(obstacle.EdgeLeft))
                            {
                                if (ball.VelocityX > 0)
                                {
                                    bounceOffObstacleLeftSide();
                                }
                                if (ball.VelocityY < 0)
                                {
                                    bounceOffObstacleBot();
                                }
                            }
                            else
                                bounceOffObstacleBot();
                        }
                        // If ball hits left side of the obstacle, bounce off the left side
                        else if (ball.Intersects(obstacle.EdgeLeft))
                        {
                            bounceOffObstacleLeftSide();
                        }
                        // If ball hits right side of the obstacle, bounce off the right side
                        else if (ball.Intersects(obstacle.EdgeRight))
                        {
                            bounceOffObstacleRightSide();
                        }
                    }
                }
            }

            else if (ball.PositionX < batLeft.Right + ball.Speed)
            {
                // Ball hits left side bat
                if (ball.Intersects(batLeft))
                {
                    ball.BounceOffBat(batLeft);
                    ball.BatLastHit = batLeft;
                }

                // Ball escapes left side of screen
                if (ball.Right < 0)
                {
                    Score.GetInstance().ScoreRight++;
                    ball.Reset(1);
                }
            }

            else if (ball.Right > batRight.Left - ball.Speed)
            {
                // Ball escapes right side of screen
                if (ball.Left > Game.WindowWidth)
                {
                    Score.GetInstance().ScoreLeft++;
                    ball.Reset(-1);
                }

                // Ball hits right side bat
                else if (ball.Intersects(batRight))
                {
                    ball.BounceOffBat(batRight);
                    ball.BatLastHit = batRight;
                }

            }

            // Ball hits top or bottom of screen
            if ((ball.Top <= 0) || (ball.Bottom >= Game.WindowHeight))
            {
                ball.VelocityY *= -1.05f;
            }
        }

        public static void ReplaceAllObstacles(List<Obstacle> obstacles)
        {
            activeObstacles = obstacles;
        }
    }
}
